/**
 * @file Thread.cpp
 *
 *  @date 2009-06-04
 *  @author manfred
 */

#include <Bust/Threads/Thread.hpp>
#include "PrivateData.hpp"

#include <windows.h>

namespace bust
{

bool Thread::_isInitialized = false;

class ThreadPrivateActions
{
friend class Thread;
private:
	static DWORD __stdcall StartThread(void* data)
	{
		Thread* thread = static_cast<Thread*>(data);
		ThreadPrivateData* pd =	static_cast<ThreadPrivateData*>(thread->_data);

		pd->isRunning = true;
		thread->run();
		pd->isRunning = false;
		return 0;
	}
};

Thread::Thread()
{
	if(!_isInitialized)
		init();

	ThreadPrivateData* pd = new ThreadPrivateData;
	pd->isRunning = false;
	pd->isCanceled = false;

	_data = pd;
}

Thread::~Thread()
{
	ThreadPrivateData* pd = static_cast<ThreadPrivateData*>(_data);
	
	cancel();	
	CloseHandle(pd->hThread);
	delete pd;	
}

void Thread::init()
{
	_isInitialized = true;
}

int Thread::start()
{
	ThreadPrivateData* pd = static_cast<ThreadPrivateData*>(_data);

	pd->hThread = CreateThread(0, 0, &ThreadPrivateActions::StartThread, this, 0, 0);
	if(!pd->hThread)
		return GetLastError();

	pd->isRunning = true;
	return 0;
}

int Thread::join()
{
	ThreadPrivateData* pd = static_cast<ThreadPrivateData*>(_data);

	WaitForSingleObject(pd->hThread, INFINITE);

	return 0;
}

int Thread::cancel()
{
	ThreadPrivateData* pd = static_cast<ThreadPrivateData*>(_data);

	pd->isCanceled = true;
	TerminateThread(pd->hThread, 0);

	return 0;
}

bool Thread::isRunning()
{
	ThreadPrivateData* pd = static_cast<ThreadPrivateData*>(_data);
	return pd->isRunning;
}

bool Thread::isCanceled()
{
	ThreadPrivateData* pd = static_cast<ThreadPrivateData*>(_data);
	return pd->isCanceled;
}

int Thread::yield()
{
	return SwitchToThread();
}

}
